<template>
  <!-- 卡片 -->
  <el-card class="box-card">
    <template #header>
      <div class="card-header">
        <el-button @click="showTrademarkDialog" type="primary" :icon="Plus">添加</el-button>
      </div>
    </template>
    <!-- 表格 -->
    <el-table v-loading="loading" :data="trademarkList" border style="width: 100%">
      <el-table-column type="index" align="center" label="序号" width="180" />
      <el-table-column prop="tmName" label="品牌名称" />
      <el-table-column label="品牌LOGO">
        <!-- 为什么要插槽来放图片 -->
        <template v-slot="{ row }">
          <img :src="row.logoUrl" alt="" style="width: 100px; height: 100px" />
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button size="large" type="warning" :icon="Edit" title="修改" @click="editTrademark(row)" />
          <el-button size="large" type="danger" :icon="Delete" @click="removeTrademark(row)" title="删除" />
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页器 -->
    <div class="demo-pagination-block">
      <div class="demonstration"></div>
      <el-pagination
        v-model:currentPage="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="[5, 7, 13]"
        :small="small"
        :disabled="disabled"
        :background="background"
        layout=" prev, pager, next, jumper,->, sizes,total,"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
    <!-- 点击添加按钮,弹出对话框 -->
    <el-dialog v-model="dialogFormVisible" :title="`${trademark.tmName ? '修改品牌' : '添加品牌'}`" draggable>
      <el-form :model="trademark" :rules="rules" ref="ruleFormRef" :size="formSize">
        <el-form-item label="品牌名称:" prop="tmName" :label-width="formLabelWidth" style="width: 75%">
          <el-input v-model="trademark.tmName" autocomplete="off" />
        </el-form-item>
        <!-- 这里不要用button按钮,因为我们需要上传图片,将图片地址存入服务器 需要去ele-plus中找到上传的组件 -->

        <!-- <el-form-item label="品牌LOGO:" :label-width="formLabelWidth">
          <el-button v-model="form.region" :icon="Plus"> </el-button>
          <br />
          <p>只能上传图片jpg文件,且不能超过50k</p>
        </el-form-item> -->
        <el-form-item label="品牌LOGO:" prop="logoUrl" :label-width="formLabelWidth">
          <!-- 因为我们要用actions来发送请求,上传图片,于是将请求的地址直接写在actions中,并且在env文件中配置了/app-dev ,并且由于我们是需要在不同环境运行,比如开发.测试.生产...所以我们需要在路径前加上/app-dev  -->
          <el-upload class="avatar-uploader" :action="`${base_url}/admin/product/upload`" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
            <img v-if="trademark.logoUrl" :src="trademark.logoUrl" class="avatar" />
            <el-icon v-else class="avatar-uploader-icon"><Plus /> </el-icon>
            <template #tip>
              <br />
              只能上传图片jpg文件,且不能超过2m
            </template>
          </el-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogFormVisible = false">返回</el-button>
          <el-button type="primary" @click="submitForm(ruleFormRef)">确认</el-button>
        </span>
      </template>
    </el-dialog>
  </el-card>
</template>
<script lang="ts">
export default {
  // 这里有一个问题,我们使用的setup语法糖的形式来写的,但是在vuex插件中,由于我们没写名字,所以我们可以在加一个script标签,专门用来添加一个name
  name: "trademark",
  // 作用之一就是在vuex中可以看到这个插件
}
</script>

<script lang="ts" setup>
// 引入ele自带
import { ElMessage, ElMessageBox } from "element-plus"
import type { UploadProps } from "element-plus"

// 引入图标
import { Plus, Edit, Delete } from "@element-plus/icons-vue"
// 响应回来的数据
import { reqGetTrademarkListData, reqAddTrademarkListData, reqDelTrademarkListData, reqUpdateTrademarkInfo } from "@/api/product/tradmark"
// 引入组合式APi
import { onMounted, reactive, ref } from "vue"
// 引入loading加载效果
// 引入ts数据约束
// 记住,一定得使用type告诉编辑器是用ts进行类型推断的
import type { TrademarkListModel, TrademarkModel } from "@/api/product/model/tradmarkmodel"
// 引入匹配规则项
import type { FormInstance, FormRules } from "element-plus"

// 弹出框相关数据
const dialogFormVisible = ref(false)
const formLabelWidth = "140px"
// const imageUrl = ref("")
const initTrademark = () => ({ tmName: "", logoUrl: "" })
// const trademark = reactive<TrademarkModel>({
//   // 这里也需要将数据进行约束,但是在之前定义的约束中,多了一个id,所以我们回到之前那个约束中,给id加个?,标识可选
//   logoUrl: "",
//   tmName: "",
// })
// 可以简写为
const trademark = reactive<TrademarkModel>(initTrademark())

// 分页器    定义数据拿来发送请求
let trademarkList = ref<TrademarkListModel>([])
// 对trademarkList进行数据类型推断,这样下面的赋值操作就不会报警告了

const currentPage = ref(1) // 当前的页码
const pageSize = ref(5) // 当前的每页
const small = ref(false)
const background = ref(false)
const disabled = ref(false)
// 如果不给total一个默认值的话,控制台会报一个警告,说已被废弃的一个用法 我们需要加一个初始值
const total = ref(0)

// console.log("base", import.meta.env.VITE_API_URL) // 查看全局配置的路径
const base_url = import.meta.env.VITE_API_URL
// 加载动画
const loading = ref(true)

// 上传校验规则
// 1.去ele中的form中找到校验规则的组件,然后根据例子来黏贴,在模板中使用rules和prop来对需要校验的表单和对应元素进行绑定,然后引入需要的方法,如下
// 2.将之前的判断条件和发请求的函数,放在校验成功的函数中的回调中
// 3.还一个需要注意的是，如果当用户校验失败时，下次在此进入，需要及时的清除校验规则，否则会一直爆红，用户体验不好
const formSize = ref("default")
const ruleFormRef = ref<FormInstance>()
// 对应的表单元素的校验规则
// 需要那个元素添加那个,并且可添加多条规则
const rules = reactive<FormRules>({
  tmName: [
    { required: true, message: "品牌名称不能为空,请输入", trigger: "blur" },
    { min: 1, max: 6, message: "品牌名称介于1--6个字符之间,请重输", trigger: "blur" },
  ],
  // required:必填,message错误提示,trigger触发条件
  logoUrl: [{ required: true, message: "请上传图片", trigger: "change" }],
})
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate((valid, fields) => {
    if (valid) {
      // 校验成功
      if (trademark.id) {
        reqUpdateTrademarkInfo(trademark)
        // 有id,说明是修改
      } else {
        // 发送请求 添加请求
        reqAddTrademarkListData(trademark)
      }
      // 弹一个消息框,提示添加成功
      ElMessage({
        message: "成功",
        type: "success",
      })
      // 为了增强用户体验,我们可以在添加成功后将数据跳转到第一页,或者最后一页
      currentPage.value = 1

      // console.log(result) // 服务器响应数据为空
      // 关闭弹出框
      dialogFormVisible.value = false
      // 重新发送请求
      getTrademarkListData()
    } else {
      // 有一项没通过就是false,执行下面代码
      console.log("error submit!", fields)
    }
  })
}

// 注意执行时机,发送请求的函数最好放在最前面
// 定义一个方法来获取数据 由于这个方法在分页器也会用到,所以将该方法封装起来
const getTrademarkListData = async () => {
  loading.value = true
  // 记住,使用ref数据,必须要用.value的形式使用
  const result = await reqGetTrademarkListData(currentPage.value, pageSize.value)
  // console.log("trademark", result)
  trademarkList.value = result.records
  // 注意:这里必须使用.value的形式来存入数据,因为trademark是被代理的数据,不使用.value的形式无法设置成响应式
  // 将total数据赋值
  total.value = result.total
  // 在响应成功后将loading设置为false
  loading.value = false
}

// 分页器之 展示页面显示数据
const handleSizeChange = (val: number) => {
  // console.log(`${val} items per page`)
  // 这里的val就是修改的每页显示的数量
  // 当用户点击的时候需要重新发送请求
  pageSize.value = val
  getTrademarkListData()
}
// 分页器之 点击跳转页面
const handleCurrentChange = (val: number) => {
  // console.log(`current page: ${val}`)
  currentPage.value = val
  getTrademarkListData()
}
// 弹出框之添加清除之前数据
const showTrademarkDialog = () => {
  // 先让弹出框显示
  dialogFormVisible.value = true
  // 这里有两种方法
  // 直接让数据赋值空字符串
  // trademark.tmName = ''
  // trademark.logoUrl = ''
  // imageUrl.value = ''
  // 或者使用对象合并的方法,使用原来的初始的空值合并
  // 这时候需要将空值分开写 不然下面合并不了,为合并后值,后面的为待合并值,后面数据会覆盖前面的
  Object.assign(trademark, initTrademark())

  // // 清除校验规则。
  // 这里用到了一个?语法,这个是可选链,如果没有值,就不执行后面的操作,类似于地址栏的?,
  // 还一个写法,例如
  // const a = 0,
  // a??'嘻嘻'和 a || '拉拉'
  // 如果是?? 就会打印0,如果是||就会执行默认值拉拉,因为||会转换布尔类型进行判断,除非a的值为null或者undefined,那么两者都是打印默认值

  // 当然,如果这里添加了,在修改数据按钮哪里也需要添加清除规则
  ruleFormRef.value?.clearValidate()
}
// 弹出框之上传成功
const handleAvatarSuccess: UploadProps["onSuccess"] = (response, uploadFile) => {
  // 成功后,将图片渲染到imageUrl中,替换之前的添加图片的大按钮
  // imageUrl.value = URL.createObjectURL(uploadFile.raw!)
  // 将图片的路径保存,以便稍后发送请求使用
  trademark.logoUrl = response.data
  // console.log(trademark.logoUrl, imageUrl.value)
}
// 弹出框之请求成功前 这个方法一般用来判断图片是否合格---常用来做限定图片的操作
const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => {
  const Filetype = ["image/jpeg", "image/jpg", "image/png"]
  // console.log(rawFile)// 图片文件
  //设置一个图片格式白名单
  if (!rawFile.type.includes(rawFile.type)) {
    ElMessage.error("请上传符合要求的图片!")
    return false
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error("图片大小不能超过2M,请重新选择...!")
    return false
  }

  // 清除校验规则
  // 问题,需要在return前写,不然TMD都return了.就不执行下面的代码了
  ruleFormRef.value?.clearValidate()
  return true
}
// 弹出框之点击确定按钮, --- 后面需要添加校验规则,于是将这个函数替换.详见submitForm函数
const AddOrUpData = async (id: number) => {
  // 由于公用组件,我们需要对这个确认按钮进行判断,发送修改还是添加的请求
  if (trademark.id) {
    const result = await reqUpdateTrademarkInfo(trademark)
    // 有id,说明是修改
  } else {
    // 发送请求 添加请求
    const result = await reqAddTrademarkListData(trademark)
  }

  // 弹一个消息框,提示添加成功
  ElMessage({
    message: "成功",
    type: "success",
  })
  // 为了增强用户体验,我们可以在添加成功后将数据跳转到第一页,或者最后一页
  currentPage.value = 1

  // console.log(result) // 服务器响应数据为空
  // 关闭弹出框
  dialogFormVisible.value = false
  // 重新发送请求
  getTrademarkListData()
}

// 点击删除弹出确认框,删除数据
const removeTrademark = (raw: TrademarkModel) => {
  // 通过插槽中的raw,可以拿到当前数据的内容,id,tmname和img
  // console.log("rr", raw)
  ElMessageBox.confirm("你真的要删除这条数据吗", "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "返回",
    type: "warning",
  })
    .then(async () => {
      await reqDelTrademarkListData(raw.id as number),
        // 这个时候ts报错,提示raw.id可能是undefined,这个时候我们需要给这个数据进行断言as number
        ElMessage({
          type: "success",
          message: "删除成功",
        })
      // 重新刷新页面
      currentPage.value = trademarkList.value.length > 1 ? currentPage.value : currentPage.value - 1
      getTrademarkListData()
    })

    .catch(() => {
      ElMessage({
        type: "info",
        message: "删除失败",
      })
    })
}
// 点击修改弹出框,修改数据
// 由于修改和添加公用一个组件, 于是我们在进入组件的时候要判断这次操作是修改还是添加
// 其二由于公用一个组件,中的确认按钮也需要进行判断
const editTrademark = (row: TrademarkModel) => {
  // 将需要显示出来的品牌数据给trademark进行赋值，因为数据是响应式的，页面会渲染出来
  // 还是使用对象的assign方法,将对象合并,这里row可以拿到当前的值,刚好合并到trademark中,形成响应式
  Object.assign(trademark, row) // 注意 此时的row当中，是有id的

  ruleFormRef.value?.clearValidate() // 清除校验规则
  dialogFormVisible.value = true // 显示对话框
}

// 一上来挂载完成就要发送请求
onMounted(() => {
  // 发送请求
  getTrademarkListData()
})
</script>

<style scoped>
.el-button--text {
  margin-right: 15px;
}
.el-select {
  width: 300px;
}
.el-input {
  width: 300px;
}
.dialog-footer button:first-child {
  margin-right: 10px;
}
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>
<style>
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>
